﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ErrorContainer.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Defines the ErrorContainer type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.ComponentModel.Modelling
{
    using System.Collections.Generic;
    using System.Linq;

    public class ErrorContainer
    {
        #region Fields

        private Dictionary<string, object> _errors;

        #endregion

        public bool HasErrors
        {
            get { return _errors != null && _errors.Count > 0; }
        }

        public bool ClearErrors()
        {
            if (_errors != null)
            {
                _errors = null;
                return true;
            }
            return false;
        }

        public bool ClearErrors(string propertyName)
        {
            if (_errors != null && _errors.Remove(propertyName))
            {
                if (_errors.Count == 0)
                {
                    _errors = null;
                }
                return true;
            }
            return false;
        }

        public bool AddError(string propertyName, string error)
        {
            if (_errors == null)
            {
                _errors = new Dictionary<string, object> { { propertyName, error } };
                return true;
            }

            // lookup entry, if not found then create new
            object entry;
            if (!_errors.TryGetValue(propertyName, out entry))
            {
                _errors[propertyName] = error;
                return true;
            }

            // handle list entry
            var errorListEntry = entry as List<string>;
            if (errorListEntry != null)
            {
                if (!errorListEntry.Contains(error))
                {
                    errorListEntry.Add(error);
                    return true;
                }
            }
            else
            {
                // handle string entry
                var errorStringEntry = (string)entry;
                if (errorStringEntry != error)
                {
                    _errors[propertyName] = new List<string> { errorStringEntry, error };
                    return true;
                }
            }
            return false;
        }

        public bool RemoveError(string propertyName, string error)
        {
            if (_errors == null)
            {
                return false;
            }

            object entry;
            if (!_errors.TryGetValue(propertyName, out entry))
            {
                return false;
            }

            // get list entry
            var errorListEntry = entry as List<string>;
            if (errorListEntry != null)
            {
                var index = errorListEntry.IndexOf(error);
                if (index == -1)
                {
                    return false;
                }

                if (errorListEntry.Count > 2)
                {
                    errorListEntry.RemoveAt(index);
                }
                else
                {
                    _errors[propertyName] = errorListEntry[index == 0 ? 1 : 0];
                }

                return true;
            }

            // get string entry
            var errorStringEntry = (string)entry;
            if (errorStringEntry != error)
            {
                return false;
            }

            // if we are the last item then dispose of the dictionary, otherwise remove the entry
            if (_errors.Count == 1)
            {
                _errors = null;
            }
            else
            {
                _errors.Remove(propertyName);
            }

            return true;
        }

        public IEnumerable<string> GetErrors(string propertyName)
        {
            object entry;
            if (_errors != null && _errors.TryGetValue(propertyName, out entry))
            {
                var listEntry = entry as List<string>;
                if (listEntry != null)
                {
                    return listEntry;
                }

                return new[] { (string)entry };
            }

            return Enumerable.Empty<string>();
        }
    }
}